// const SIMULATE_COUNT = Number.MAX_SAFE_INTEGER;
const SIMULATE_COUNT = 9 * 1e6 - 1;

const STRATEGY_OPEN_FIST_EMPTY = 1;
const STRATEGY_OPEN_RANDOM_REMPTY = 2;

const OpenStrategyNames = {
  [STRATEGY_OPEN_FIST_EMPTY]: "选择第一个空门",
  [STRATEGY_OPEN_RANDOM_REMPTY]: "随机打开一个空门",
};

const STRATEGY_ALWAYS_KEEP_CHOICE = 1;
const STRATEGY_ALWAYS_CHANGE_CHOICE = 2;
const STRATEGY_CONDITIONAL_CHANGE_CHOICE = 3;

const ChangeChoiceNames = {
  [STRATEGY_ALWAYS_KEEP_CHOICE]: "始终保留原先的选择",
  [STRATEGY_ALWAYS_CHANGE_CHOICE]: "改变选择",
  [STRATEGY_CONDITIONAL_CHANGE_CHOICE]: "有条件的改变选择",
};

/**
 * 当打开的是较小的门的时候改变选择，否则保留选择
 * */
const CHANGE_CHOICE_CONDITION_1 = 1;
/**
 * 当打开的是较大的门的时候改变选择，否则保留选择
 * */
const CHANGE_CHOICE_CONDITION_2 = 2;

const ChangeChoiceConditionNames = {
  [CHANGE_CHOICE_CONDITION_1]: "当打开的是较小的门的时候改变选择，否则保留选择",
  [CHANGE_CHOICE_CONDITION_2]: "当打开的是较大的门的时候改变选择，否则保留选择",
};

let openStrategy = STRATEGY_OPEN_RANDOM_REMPTY;
let changeStrategy = STRATEGY_CONDITIONAL_CHANGE_CHOICE;
let conditionStrategy = CHANGE_CHOICE_CONDITION_2;

function init() {
  const awardPos = Math.floor(Math.random() * 3);
  const doors = new Array(3).fill(0);
  doors[awardPos] = 1;

  return doors;
}

function judge(seed, picked) {
  return seed[picked] === 1;
}

function pick() {
  const pickedPos = Math.floor(Math.random() * 3);
  return pickedPos;
}

function openEmptyDoor(seed, picked) {
  // 原来的选择会中奖 1/3 概率
  if (seed[picked] === 1) {
    switch (openStrategy) {
      case STRATEGY_OPEN_FIST_EMPTY:
        // 策略一，始终选择靠前的空格
        for (let i = 0; i < 3; i++) {
          if (i !== picked) {
            return i;
          }
        }
        break;
      case STRATEGY_OPEN_RANDOM_REMPTY: {
        // 策略二，随机选择一个空格
        const openChoice = Math.floor(Math.random() * 2);
        let ite = 0;
        for (let i = 0; i < 3; i++) {
          if (i === picked) {
            continue;
          }

          if (ite === openChoice) {
            return i;
          }

          ite += 1;
        }
        break;
      }
    }
  } else {
    // 原来选择的不会中奖, 2/3 概率
    // 只有一个策略，选择剩下的空格
    for (let i = 0; i < 3; i++) {
      if (i !== picked && seed[i] !== 1) {
        return i;
      }
    }
  }
}

function changeOrKeepChoice(seed, picked, opened) {
  // 策略一，始终不改变选择
  switch (changeStrategy) {
    case STRATEGY_ALWAYS_KEEP_CHOICE:
      return [seed, picked];
    case STRATEGY_ALWAYS_CHANGE_CHOICE: {
      for (let i = 0; i < 3; ++i) {
        if (i !== picked && i !== opened) {
          return i;
        }
      }
      break;
    }
    case STRATEGY_CONDITIONAL_CHANGE_CHOICE: {
      // 策略二，始终变更选择
      let leftOne = -1;
      for (let i = 0; i < 3; ++i) {
        if (i !== picked && i !== opened) {
          leftOne = i;
          break;
        }
      }

      if (conditionStrategy === CHANGE_CHOICE_CONDITION_1) {
        // 策略三，如果开启的是剩下的门中靠后的门，则改变主意； 否则不改变
        if (leftOne > opened) {
          return leftOne;
        } else {
          return picked;
        }
      } else {
        // 策略三，如果开启的是剩下的门中靠后的门，则改变主意； 否则不改变
        if (leftOne < opened) {
          return leftOne;
        } else {
          return picked;
        }
      }
    }
  }
}

function simulate() {
  console.log(`即将模拟 ${SIMULATE_COUNT} 次试验`);
  console.log(`开门策略：${OpenStrategyNames[openStrategy]}`);
  console.log(
    `变更策略: ${ChangeChoiceNames[changeStrategy]} -- ${ChangeChoiceConditionNames[conditionStrategy]}`,
  );

  let successTimes = 0;

  for (let i = 0; i < SIMULATE_COUNT; ++i) {
    const seed = init(); // 这里每个格子等概率
    const picked = pick(); // 这里中奖概率1/3

    const opened = openEmptyDoor(seed, picked);

    // 这里加一个断言，因为这里容易出错
    if (seed[opened] === 1) {
      console.error("ERROR");
      return -1;
    }

    const pickedSecondTime = changeOrKeepChoice(seed, picked, opened);

    if (judge(seed, pickedSecondTime)) {
      successTimes += 1;
    }
  }

  console.log(
    `最终中奖次数： ${successTimes} 中奖概率： ${
      successTimes / SIMULATE_COUNT
    }`,
  );
}

simulate();
